/*!
 * \file weblogic_ejb.c
 *
 * \brief weblogic ejb 数据包解析
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 *
 * \version 3.0
 * \author wuwk
 * \date 2016/01/22
 *
 */

#include <stdio.h>

#include "corba_comm.h"
#include "weblogic_ejb.h"
#include "ejb_comm.h"


/*!
 * iiop weblogic ejb名解析
 *
 * \param *p_st_session_private        (corba_session  私有数据)
 * \param *p_st_data                   (Frbyte_Packet  数据)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
FR_STATIC int __weblogic_get_ejbname(corba_session *p_st_session_private
                                   , Frbyte_Packet *p_st_data)
{
    L7session_corba_private *p_st_private = NULL;
    char *p_ejb_name = NULL;
    uint32_t u32_len = 0;
    int i_idx = 0;
    int i_idx2 = 0;

    if (p_st_session_private == NULL || p_st_session_private->p_st_private == NULL || p_st_data == NULL)
        return FR_FAIL;

    p_st_private = p_st_session_private->p_st_private;

    if (bytebuff_memstr(p_st_data, bytebuff_getPosition(p_st_data), 0, WEBLOGIC_EJB_REMOTEPROXY, strlen(WEBLOGIC_EJB_REMOTEPROXY), &i_idx) == FR_FAIL)
        return FR_SUCC;

    bytebuff_setPosition(p_st_data, i_idx);
    if (bytebuff_memstr(p_st_data, bytebuff_getPosition(p_st_data), 0, CORBA_IDL_STRINGVALUE, strlen(CORBA_IDL_STRINGVALUE), &i_idx2) == FR_FAIL)
        return FR_FAIL;

    bytebuff_setPosition(p_st_data, i_idx2-4);
    // skip CORBA_IDL_STRINGVALUE
    if (skip_utf(p_st_data) == FR_FAIL)
        return FR_FAIL;

    // 00 + 总长(ejb名长度+ejb名)
    bytebuff_skip(p_st_data, 5);

    if (bytebuff_get_int(p_st_data, 4, &u32_len, BYTE_BIG_ENDIAN) == FR_FAIL)
        return FR_FAIL;

    p_ejb_name = (char *)frmalloc(u32_len + 1);
    if (p_ejb_name == NULL)
        return FR_FAIL;

    // 取ejb名并去掉最后一个‘@’
    if (bytebuff_get_bytes(p_st_data, p_ejb_name, u32_len) == FR_FAIL)
    {
        frfree(p_ejb_name);
        return FR_FAIL;
    }
    p_ejb_name[u32_len-1] = '\0';

    // ejb名做为title
    if (p_st_private->p_title)
        frfree(p_st_private->p_title);

    p_st_session_private->p_wls_ejbname = frstrdup(p_ejb_name);
    if (p_st_session_private->p_wls_ejbname == NULL)
    {
        frfree(p_ejb_name);
        return FR_FAIL;
    }

    p_st_private->p_title = p_ejb_name;
    p_st_session_private->is_wls_ejb = 1;

    return FR_SUCC;
}

/*!
 * iiop weblogic ejb响应(string,object)解析
 *
 * \param *p_st_data           (Frbyte_Packet         数据)
 * \param *p_st_body_data      (Frreport_body_data    上报数据)
 * \param *p_key               (char    上报key)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
FR_STATIC int __weblogic_resp_object(Frbyte_Packet *p_st_data
                                   , Frreport_body_data *p_st_body_data
                                   , char *p_key
                                   , int i_pos)
{
    char *p_object = NULL;
    char *p_data = NULL;
    uint32_t u32_chunk = 0;
    uint32_t u32_obj_len = 0;
    uint32_t u32_data_len = 0;
    uint32_t u32_count = 0;
    int i_remain_len = 0;

    if (p_st_data == NULL || p_st_body_data == NULL || p_key == NULL)
        return FR_FAIL;

    i_remain_len = bytebuff_remaining(p_st_data);
    if (i_remain_len < 4)
        return FR_FAIL;

    if (bytebuff_peek_int(p_st_data, 4, &u32_chunk, BYTE_BIG_ENDIAN) == FR_FAIL)
        return FR_FAIL;

    // 7f ff ff 02
    if (u32_chunk != 2147483394 && u32_chunk != 2147483402)
        return FR_SUCC;

    bytebuff_skip(p_st_data, 4);

    if (bytebuff_get_int(p_st_data, 4, &u32_obj_len, BYTE_BIG_ENDIAN) == FR_FAIL)
        return FR_FAIL;

    p_object = (char *)frmalloc(u32_obj_len + 1);
    if (p_object == NULL)
        return FR_FAIL;

    if (bytebuff_get_bytes(p_st_data, p_object, u32_obj_len) == FR_FAIL)
    {
        frfree(p_object);
        return FR_FAIL;
    }

    if (u32_obj_len == 35 && strncmp(p_object, CORBA_IDL_STRINGVALUE, 34) == 0)
    {
        frfree(p_object);
        // string
        bytebuff_skip(p_st_data, 1); //对齐

        if (bytebuff_get_int(p_st_data, 4, &u32_data_len, BYTE_BIG_ENDIAN) == FR_FAIL)
            return FR_FAIL;

        p_data = (char *)frmalloc(u32_data_len + 1);
        if (p_data == NULL)
            return FR_FAIL;

        if (bytebuff_get_bytes(p_st_data, p_data, u32_data_len) == FR_FAIL)
        {
            frfree(p_data);
            return FR_FAIL;
        }
        p_data[u32_data_len] = '\0';

        if (frreport_body_l7_add_str(p_st_body_data, p_key, p_data) == FR_FAIL)
        {
            frfree(p_data);
            return FR_FAIL;
        }
        frfree(p_data);
    }
    else if (strncmp(p_object, RMI_ARRAY, 5) == 0)
    {
        // 对齐
        if (__alignment(p_st_data, i_pos, 4) == FR_FAIL)
            return FR_FAIL;

        if (bytebuff_get_int(p_st_data, 4, &u32_count, BYTE_BIG_ENDIAN) == FR_FAIL)
        {
            frfree(p_object);
            return FR_FAIL;
        }
        switch (*(p_object+5))
        {
            case 'B':
                if (ejb_rtn_byte_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'C':
                if (ejb_rtn_char_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'S':
                if (ejb_rtn_short_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    return FR_FAIL;
                break;
            case 'I':
                if (ejb_rtn_int_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'J':
                if (ejb_rtn_long_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'F':
                if (ejb_rtn_float_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'D':
                if (ejb_rtn_double_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'Z':
                if (ejb_rtn_boolean_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'L':
                if (strncmp(p_object + 6, RMI_JAVA_STRING, strlen(RMI_JAVA_STRING)) == 0)
                {
                    if (ejb_rtn_string_array(p_st_data, p_st_body_data, u32_count, p_key, i_pos, IS_WEBLOGIC) == FR_FAIL)
                        goto err;
                }
                else if (strncmp(p_object + 6, RMI_JAVA_OBJECT, strlen(RMI_JAVA_OBJECT)) == 0)
                {
                    i_remain_len = bytebuff_remaining(p_st_data);
                    // 上报
                    if (frreport_body_l7_add_bin(p_st_body_data, p_key, NULL, i_remain_len) == FR_FAIL)
                        goto err;

                    bytebuff_skip(p_st_data, i_remain_len);
                }
                break;
            default:
                break;
        }
        frfree(p_object);
    }
    else
    {
        frfree(p_object);
        return FR_SUCC;
    }

    return FR_SUCC;

err:
    if (p_object)
        frfree(p_object);

    return FR_FAIL;
}

/*!
 * iiop weblogic ejb响应解析
 *
 * \param *p_st_data           (Frbyte_Packet         数据)
 * \param *p_st_body_data      (Frreport_body_data    上报数据)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
FR_STATIC int __weblogic_resp_report(corba_session *p_st_session_private
                                   , Frbyte_Packet *p_st_data
                                   , Frreport_body_data *p_st_body_data)
{
    char *p_data = NULL;
    char arr_key[64];
    int i_remain_len = 0;
    int i_ret = 0;

    if (p_st_session_private == NULL || p_st_data == NULL || p_st_body_data == NULL)
        return FR_FAIL;

    i_remain_len = bytebuff_remaining(p_st_data);

    snprintf(arr_key, sizeof(arr_key), "%s.1.1", EJB_FUNC_RESP);
    switch (i_remain_len)
    {
        case 1:
        case 2:
        case 4:
        case 8:
            p_data = (char *)frmalloc(i_remain_len + 1);
            if (p_data == NULL)
                return FR_FAIL;

            if (bytebuff_get_bytes(p_st_data, p_data, i_remain_len) == FR_FAIL)
            {
                frfree(p_data);
                return FR_FAIL;
            }

            if (frreport_body_l7_add_bin(p_st_body_data, arr_key, p_data, i_remain_len) == FR_FAIL)
            {
                frfree(p_data);
                return FR_FAIL;
            }
            frfree(p_data);

            break;
        default:
            p_st_session_private->i_pos = bytebuff_getPosition(p_st_data);

            i_ret = __weblogic_resp_object(p_st_data, p_st_body_data, arr_key, p_st_session_private->i_pos);
            if (i_ret == FR_FAIL)
                return FR_FAIL;

            break;
    }

    return FR_SUCC;
}

/*!
 * iiop weblogic ejb 请求解析
 *
 * \param *p_st_session_private        (corba_session         私有数据)
 * \param *p_st_body_data              (Frreport_body_data    上报数据)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
int weblogic_ejb_parse_req(corba_session *p_st_session_private
                         , Frreport_body_data *p_st_body_data)
{
    char arr_key[64];
    L7session_corba_private *p_st_private = NULL;

    if (p_st_session_private == NULL || p_st_body_data == NULL || p_st_session_private->p_st_private == NULL)
        return FR_FAIL;

    p_st_private = p_st_session_private->p_st_private;
    // 更新title
    if (p_st_session_private->p_wls_ejbname)
    {
        if (p_st_private->p_title)
            frfree(p_st_private->p_title);

        p_st_private->p_title = frstrdup(p_st_session_private->p_wls_ejbname);
        if (p_st_private->p_title == NULL)
            return FR_FAIL;
    }

    if (p_st_session_private->p_wls_function == NULL)
        return FR_FAIL;

    snprintf(arr_key, sizeof(arr_key), "%s", EJB_FUNC);
    if (frreport_body_l7_add_str(p_st_body_data, arr_key, p_st_session_private->p_wls_function) == FR_FAIL)
        return FR_FAIL;

    return FR_SUCC;
}

/*!
 * iiop weblogic ejb 响应解析
 *
 * \param *p_st_session_private        (corba_session  私有数据)
 * \param *p_st_data                   (Frbyte_Packet         数据)
 * \param *p_st_body_data              (Frreport_body_data    上报数据)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
int weblogic_ejb_parse_resp(corba_session *p_st_session_private
                          , Frbyte_Packet *p_st_data
                          , Frreport_body_data *p_st_body_data)
{
    L7session_corba_private *p_st_private = NULL;
    int i_ret = 0;

    if (p_st_session_private == NULL || p_st_data == NULL || p_st_body_data == NULL
        || p_st_session_private->p_st_private == NULL)
        return FR_FAIL;

    p_st_private = p_st_session_private->p_st_private;

    if (p_st_session_private->is_wls_ejb == 0)
        i_ret = __weblogic_get_ejbname(p_st_session_private, p_st_data);
    else
        i_ret = __weblogic_resp_report(p_st_session_private, p_st_data, p_st_body_data);

    return i_ret;
}
